/*
package com.lnn;

*/
/**
 * @author: Li Ning Ning
 * @since: 2022/2/18 14:58
 * @version: 1.0
 *//*


import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class HopField {
    private static final double R = 6371.004;
    private int cityNum;//城市数量
    private int MAX;//迭代次数
    //private double bestLength;
    private int[] bestTour;
    private double[][] distance;//距离矩阵
    //private double[][] time;//时间矩阵
    double[] xx;//用来输出最佳路径每个城市位置
    double[] yy;//用来输出最佳路径每个城市位置
    private String filepath;
    private double A,D;
    private double U0;
    //private double[][][][] W;//权值矩阵
    private double[][] deltaU;//动态结果
    private double[][] V;//换位矩阵
    private double[][] Ut;//下一刻输入
    private double[][] U;//初始值
    private double step;//步长，即delta t
    private double E;//能量值

    public HopField(int MAX, int cityNum, double U0, double step, double A, double D, String filepath) {
        this.MAX = MAX;
        this.cityNum = cityNum;
        this.U0 = U0;
        this.step = step;
        this.A = A;
        this.D = D;
        this.filepath = filepath;
        bestTour = new int [cityNum];
        distance = new double[cityNum][cityNum];
        W = new double[cityNum][cityNum][cityNum][cityNum];
        V = new double[cityNum][cityNum];
        deltaU = new double[cityNum][cityNum];
        Ut = new double[cityNum][cityNum];
        U = new double[cityNum][cityNum];
        xx = new double[cityNum];
        yy = new double[cityNum];
    }

    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }

    //计算距离矩阵
    public double[][] Distance() throws BiffException, IOException{
        double[] x = new double[cityNum];
        double[] y = new double[cityNum];
        distance = new double[cityNum][cityNum];
        //创建输入流
        InputStream stream = new FileInputStream(filepath);
        //获取Excel文件对象
        Workbook  rwb = Workbook.getWorkbook(stream);
        //获取文件的指定工作表 默认的第一个
        Sheet sheet = rwb.getSheet("Sheet2");

        for(int i=0;i<sheet.getRows();i++) {
            NumberCell cell = null;//解决了Cell只保留三位小数的问题
            cell = (NumberCell) sheet.getCell(0,i);
            x[i] = cell.getValue();
            xx[i] = x[i];
            cell = (NumberCell) sheet.getCell(1,i);
            y[i] = cell.getValue();
            yy[i] = y[i];

        }
        //计算每个城市间距离
        for (int i = 0; i < cityNum - 1; i++) {
            distance[i][i] = 0; // 对角线为0
            //将经纬度转换为平面距离
            for (int j = i + 1; j < cityNum; j++) {
                double rij = 2*R*Math.asin(Math.sqrt(Math.pow(Math.sin((rad(y[j])-rad(y[i]))/2), 2) + Math.cos(rad(y[j]))*Math.cos(rad(y[i]))*Math.pow(Math.sin((rad(x[j])-rad(x[i]))/2), 2)));
                distance[i][j] = rij;
                distance[j][i] = distance[i][j];
            }
        }
        distance[cityNum - 1][cityNum - 1] = 0;
        return distance;
    }

    //神经网络动态方程
    public double[][] calc_du(double[][] V,double[][] distance) {
        double[] a1 = new double[cityNum];
        double[] a2 = new double[cityNum];
        double[] b = new double[cityNum];
        double[][] t1 = new double[cityNum][cityNum];
        double[][] t2 = new double[cityNum][cityNum];
        double[][] d = new double[distance.length][V[0].length];
        //按列相加
        for(int x=0;x<cityNum;x++) {
            for(int i=0;i<cityNum;i++) {
                a1[x] += V[x][i];
            }
        }
        for(int i=0;i<cityNum;i++) {
            for(int j=0;j<cityNum;j++) {
                t1[i][j] = a1[j];
            }
        }
        //按行相加
        for(int y=0;y<cityNum;y++) {
            for(int i=0;i<cityNum;i++) {
                a2[i] += V[i][y];
            }
        }
        for(int i=0;i<cityNum;i++) {
            for(int j=0;j<cityNum;j++) {
                t2[j][i] = a2[j];
            }
        }
        //将第一列放在最后一列
        for(int i=0;i<cityNum;i++) {
            b[i] = V[i][0];
        }
        for(int i=0;i<cityNum;i++) {
            for(int j=0;j<cityNum-1;j++) {
                V[i][j] = V[i][j+1];
            }
        }
        for(int i=0;i<cityNum;i++) {
            V[i][cityNum-1] = b[i];
        }

        double sum=0;
        for(int j=0;j<V[0].length;j++) {
            for(int k=0;k<distance.length;k++) {
                for(int i=0;i<distance[0].length;i++) {
                    sum=sum+distance[k][i]*V[i][j];
                }
                d[k][j]=sum;
                sum=0;
            }
        }
        for(int i=0;i<cityNum;i++) {
            for(int j=0;j<cityNum;j++) {
                deltaU[i][j] = -1*A*((t1[i][j]-1)+(t2[i][j]-1))-D*d[i][j];
            }
        }
        return deltaU;
    }

    //计算输出方程
    public double[][] calc_V(double[][] U) {
        for(int x=0;x<cityNum;x++) {
            for(int i=0;i<cityNum;i++) {
                V[x][i] = (1+Math.tanh(U[x][i]/U0))/2;
            }
        }
        return V;
    }

    //状态更新：下一刻状态Uxi(t0+step)
    public double[][] calc_Ut(double[][] deltaU,double[][] U) {
        for(int x=0;x<cityNum;x++) {
            for(int i=0;i<cityNum;i++) {
                Ut[x][i] = deltaU[x][i]*step + U[x][i];
            }
        }
        return Ut;
    }

    //能量公式
    public double calc_E(double[][] V,double[][] dis) {
        double[] a1 = new double[cityNum];
        double[] a2 = new double[cityNum];
        double[] b = new double[cityNum];
        double J;
        double t1=0,t2=0,t3=0;
        double[][] V1 = new double[cityNum][cityNum];
        double[][] d = new double[distance.length][V[0].length];
        //按列相加
        for(int x=0;x<cityNum;x++) {
            for(int i=0;i<cityNum;i++) {
                a1[x] += V[x][i];
            }
        }
        for(int i=0;i<cityNum;i++) {
            t1 += (a1[i]-1)*(a1[i]-1);
        }
        //按行相加
        for(int y=0;y<cityNum;y++) {
            for(int i=0;i<cityNum;i++) {
                a2[i] += V[i][y];
            }
        }
        for(int i=0;i<cityNum;i++) {
            t2 += (a2[i]-1)*(a2[i]-1);
        }

        //将第一列放在最后一列
        for(int i=0;i<cityNum;i++) {
            b[i] = V[i][0];
        }
        for(int i=0;i<cityNum;i++) {
            for(int j=0;j<cityNum-1;j++) {
                V1[i][j] = V[i][j+1];
            }
        }
        for(int i=0;i<cityNum;i++) {
            V1[i][cityNum-1] = b[i];
        }

        double sum=0;
        for(int j=0;j<V[0].length;j++) {
            for(int k=0;k<distance.length;k++) {
                for(int i=0;i<distance[0].length;i++) {
                    sum=sum+distance[k][i]*V1[i][j];
                }
                d[k][j]=sum;
                sum=0;
            }
        }
        for(int j=0;j<V[0].length;j++) {
            for(int k=0;k<distance.length;k++) {
                for(int i=0;i<distance[0].length;i++) {
                    t3 += d[k][i]*V[i][j];
                }
            }
        }
        J = (A*t1+A*t2+D*t3)/2;
        return J;

    }

    public int[] getpath(double[][] V) {
        double[] max = new double[cityNum];
        //每列最大值
        for(int j=0;j<cityNum;j++) {
            double a=0;
            for(int i=0;i<cityNum;i++) {
                if(V[i][j] > a) {
                    a = V[i][j];
                }
            }
            max[j] = a;
            //System.out.print(max[j]+",");
        }

        int j=0;
        for(int i=0;i<cityNum;i++) {
            if(max[j] == V[i][j]) {
                bestTour[j] = i;
                j++;
                break;
            }
        }
        return bestTour;
    }

    public static Object[] szqc(int[] a) {
        List list = new ArrayList();
        //遍历数组往集合里存元素
        for(int i=0;i<a.length;i++){
            //如果集合里面没有相同的元素才往里存
            if(!list.contains(a[i])){
                list.add(a[i]);
            }
        }
        //toArray()方法会返回一个包含集合所有元素的Object类型数组
        Object[] newArr = list.toArray();
        return newArr;
    }


    public void solve() throws BiffException, IOException {
        int tt[] = new int[cityNum];
        distance = Distance();
        //初始化Uxi
        System.out.println("U");
        for(int x=0;x<cityNum;x++) {
            for(int i=0;i<cityNum;i++) {
                U[x][i] = 1/2*U0*Math.log(cityNum - 1) + (Math.random()*2-1)/10;
                System.out.print(U[x][i]+"\t");
            }
            System.out.println();
        }

        //初始化输出状态
        System.out.println("V");
        V = calc_V(U);
        for(int x=0;x<cityNum;x++) {
            for(int i=0;i<cityNum;i++) {
                System.out.print(V[x][i]+"\t");
            }
            System.out.println();
        }
        //开始迭代
        for(int i=0;i<MAX;i++) {
            deltaU = calc_du(V,distance);
            Ut = calc_Ut(deltaU, U);
            U = Ut;
            V = calc_V(U);
            for(int x=0;x<cityNum;x++) {
                for(int i1=0;i1<cityNum;i1++) {
                    V[x][i1]=Math.round(V[x][i1]);
                }
            }
            E = calc_E(V,distance);
            bestTour = getpath(V);
            Object[] tour = szqc(bestTour);
            if(tour.length == bestTour.length) {
                for(int i1=0;i1<cityNum;i1++) {
                    //int x = bestTour[i];
                    System.out.print(bestTour[i1]+",");
                    tt[i1] = bestTour[i1];
                }
                System.out.println();
                double sum1=0;
                for(int i1=0;i1<cityNum-1;i1++) {

                    sum1 +=distance[bestTour[i1]][bestTour[i1+1]];
                }
                sum1 += distance[bestTour[0]][bestTour[cityNum-1]];
                System.out.println("距离："+sum1);
                System.out.println("E:"+E);
            }
        }
        for(int i=0;i<cityNum;i++) {
            System.out.print(tt[i]+",");
        }
    }
}
*/
